// INCLUDES --------------------------------------------------------------------
#include "Vector4.h"

// FUNCTIONS -------------------------------------------------------------------

/* GENERAL:
   d    -> destination
   s    -> source
   size -> array size (0,1 for single elements)

   a,b  -> two arbitrary vertices
   k    -> floating point scalar
*/

// clear to [0,0,0,1]
void Vector4Clear(Vector4 *v, ui32 size)
{
  GUARD_NULL("Vector4Clear *v", v);

  // clamp range to at least one element
  CLAMP_LOW(size, 1); 

  memset(v, 0, sizeof(Vector4)*size);            // clear vector to [0,0,0,0]
  
  i32 i;
  for (i = 0; i < (i32)size; i++) v[i].w = 1.0f; // set w=1
};

// clone vector src->dest
void Vector4Copy(Vector4 *d, Vector4 *s, ui32 size)
{
  // copy contents
  FillCopy(d, s, sizeof(Vector4), size);
};

/* the vector magnitude is defined by the pythagorean theorem for
   finding the length of a rectangular solid:

   |a| = sqrt(a² + b² + c²)

   which yields here to:

   |v| = sqrt(v.x² + v.y² + v.z²)
*/
fp Vector4Magnitude(Vector4 *v)
{
  GUARD_NULL("Vector4Magnitude *v", v, 0.0f);

  return (fp)sqrt(v->x * v->x +
                  v->y * v->y +
                  v->z * v->z);
};

/* a unit vector (denoted as â) is defined as the division of each of it's
   components by the vectors magnitude:

        a
   â = ---
       |a|

   so the result is basically:

        ax        ay        az
   âx = ---  ây = ---  âz = ---
        |a|       |a|       |a|
*/
void Vector4Normalize(Vector4 *v)
{
  fp magnitude = Vector4Magnitude(v);
  GUARD_ZERO("Vector4Normalize Magnitude", magnitude);

  fp factor = 1.0f / magnitude;
  Vector4MulTo(v, magnitude);
};

/* inverse vector from a to -a. this is done by negating every component.
   thus we retrieve:

   -a = [-(x) -(y) -(z)]
*/
void Vector4Invert(Vector4 *v) { Vector4MulTo(v, -1.0f); };

/* the scalar product (also refered to as the "dot product") is the
   resulting scalar of the sum of the products of the individual
   vector components of a and b.

   it's defined as:

   a * b = ax * bx + ay * by + az * bz
*/
fp Vector4ScalarProduct(Vector4 *a, Vector4 *b)
{
  GUARD_NULL("Vector4ScalarProduct *a", a, 0.0f);
  GUARD_NULL("Vector4ScalarProduct *b", b, 0.0f);

  return (a->x * b->x +
          a->y * b->y +
          a->z * b->z);
};

/* the vector product is defined by the expansion of the matrix

             i   j   k
   a x b = | ax  ay  az | = c
           | bx  by  bz |

   which expands to:

   a x b = [ (ay * bz - az * by)i
            -(ax * bz - az * bx)j
             (ax * by - ay * bx)k ]

   the resulting vector c is perpendicular both to a and c.
*/
void Vector4VectorProduct(Vector4 *d, Vector4 *a, Vector4 *b)
{
  GUARD_NULL("Vector4VectorProduct *d", d);
  GUARD_NULL("Vector4VectorProduct *a", a);
  GUARD_NULL("Vector4VectorProduct *b", b);

  d->x =   a->y * b->z - a->z * b->y;
  d->y = -(a->x * b->z - a->z * b->x);
  d->z =   a->x * b->y - a->y * b->x;
};

// [+, +=] ---------------------------------------------------------------------
/* vector addition:

   vector addition is done by adding up each individual component of the vector a
   with the corresponding component of the second vector b.

   thus we retrieve:

   a + b = [ax+bx ay+by az+bz]
*/
void Vector4Add(Vector4 *d, Vector4 *a, Vector4 *b)
{
  GUARD_NULL("Vector4Add *d", d);
  GUARD_NULL("Vector4Add *a", a);
  GUARD_NULL("Vector4Add *b", b);

  d->x = a->x + b->x;
  d->y = a->y + b->y;
  d->z = a->z + b->z;
};

void Vector4AddTo(Vector4 *d, Vector4 *a)
{
  GUARD_NULL("Vector4AddTo *d", d);
  GUARD_NULL("Vector4AddTo *a", a);

  d->x += a->x;
  d->y += a->y;
  d->z += a->z;
};

// [-, -=] ---------------------------------------------------------------------
/* vector subtraction:

   vector subtraction is done by subtracting each individual component
   of the second vector b from the corresponding component of the first vector a.

   thus we retrieve:

   a - b = [ax-bx ay-by az-bz]
*/
void Vector4Sub(Vector4 *d, Vector4 *a, Vector4 *b)
{
  GUARD_NULL("Vector4Sub *d", d);
  GUARD_NULL("Vector4Sub *a", a);
  GUARD_NULL("Vector4Sub *b", b);

  d->x = a->x - b->x;
  d->y = a->y - b->y;
  d->z = a->z - b->z;
};

void Vector4SubTo(Vector4 *d, Vector4 *a)
{
  GUARD_NULL("Vector4SubTo *d", d);
  GUARD_NULL("Vector4SubTo *a", a);

  d->x -= a->x;
  d->y -= a->y;
  d->z -= a->z;
};

// [*, *=] ---------------------------------------------------------------------
/* scalar multiplication:

   scalar multiplication is done by multiplicating each individual component
   of the vector a with the given scalar k.

   thus we retrieve:

   ka = [k*ax k*ay k*az]
*/
void Vector4Mul(Vector4 *d, Vector4* a, fp k)
{
  GUARD_NULL("Vector4Mul *d", d);
  GUARD_NULL("Vector4Mul *a", a);

  d->x = a->x * k;
  d->y = a->y * k;
  d->z = a->z * k;
};

void Vector4MulTo(Vector4 *d, fp k)
{
  GUARD_NULL("Vector4MulTo *d", d);

  d->x *= k;
  d->y *= k;
  d->z *= k;
};

// [/, /=] ---------------------------------------------------------------------
/* scalar division:

   scalar division is done by dividing each individual component
   of the vector a with the given scalar k.

   thus we retrieve:

   a / k = [ax/k ay/k az/k]

   for performance and safety we convert the division into a multiplication.
*/
void Vector4Div(Vector4 *d, Vector4* a, fp k)
{
  GUARD_ZERO("Vector4Div k", k);

  fp factor = 1.0f / k;
  Vector4Mul(d, a, factor);
};

void Vector4DivTo(Vector4 *d, fp k)
{
  GUARD_ZERO("Vector4DivTo k", k);

  fp factor = 1.0f / k;
  Vector4MulTo(d, factor);
};

// [==, !=] --------------------------------------------------------------------
/* vector equality

   two vectors a,b are equal if all their corresponding components are equal.

   thus we retrieve:

   a == b <-> (ax==bx, ay==by, az==bz)
*/
bool Vector4Equals(Vector4 *a, Vector4 *b)
{
  GUARD_NULL("Vector4Equals *a", a, false);
  GUARD_NULL("Vector4Equals *b", b, false);

  // binary compare the two memory structures 
  if (memcmp(a, b, sizeof(Vector4)) == 0) return true;
  else return false;
};

bool Vector4InEquals(Vector4 *a, Vector4 *b)
{
  // compare structure
  bool ret = Vector4Equals(a, b);

  // invert answer
  if (ret == true) return false;
  else return true;
};
